//
//  YDownloaderHelper.m
//  yuikemall
//
//  Created by yuike6 yuike6 on 12-3-8.
//  Copyright (c) 2012年 yuike. All rights reserved.
//

#import "YDownloaderHelper.h"
#import "YDownloadObjectModel.h"

#define _NAX_SIZE_DOWNLOAD_TASK_RELUST_IN_TASK_POOL_        200

@implementation YDownloaderHelper
@synthesize requestDictionary = requestDictionary_;
-(YFixSizeMutableDictionary *) requestDictionary
{
    @synchronized(requestDictionary_)
    {
        return requestDictionary_;
    }
}

@synthesize timeout;
- (void) dealloc
{
    YRelease(requestDictionary_);
    [super dealloc];
}

- (id) init
{
    self = [super init];
    if (self) 
    {
        YFixSizeMutableDictionary * tmp = [[YFixSizeMutableDictionary alloc] initWithCapacity:_NAX_SIZE_DOWNLOAD_TASK_RELUST_IN_TASK_POOL_];
        self.requestDictionary = tmp;
        YRelease(tmp);
        
        [self setMaxConcurrentTaskCount:4];
    }
    return self;
}

- (void) addDownloadRequest:(DownloadRequest *) request
{
    if (!request) {
        return;
    }
    
    [self.requestDictionary setObject:request forKey:request.name];
    
    YDownloaderTask * task_ = [[YDownloaderTask alloc] init];
    [task_ setName:request.name];
    [task_ setRecvData:request.recvData];
//    [task_ setDownloadModel:request.downloadModel];
    [task_ setQueuePriority:request.level];
    
    if (self.timeout != 0) 
    {
        [task_ setTimeout:self.timeout];
    }
    
    [task_ setDelegate:self];       
    [task_ download:request.downloadModel];
    
    [self addTask:task_];    
    DebugLog(@"task added count:%d, url is:%@, name is: %@", 
             self.taskCount, 
             [request.downloadModel url],
             task_.name);
    
    YRelease(task_);
}

- (void) cancelDownloadRequest:(DownloadRequest *) request
{
    if (!request) 
    {
        return;
    }
    
    [self cancelDownloadRequestByName:request.name];
}

- (void) cancelDownloadRequestByName:(NSString *) requestName
{
    
    if ([NSString isNilOrEmpty:requestName]) 
    {
        return;
    }
    
    YDownloaderTask * task = (YDownloaderTask *) [self taskByName:requestName];
    if (!task) 
    {
        return;
    }

    if ([task.recvData isRecvFinished]) {
        return;
    }
    
        
    DebugLog(@"stop unFinish Task:%@", requestName);
    [self stopTaskByName:requestName]; 
//    [self cancelTaskByName:requestName];
//    [self.requestDictionary removeObjectForKey:requestName];
}

- (void) stopAllRequest
{
    [self stopAllTask];
    [self cancelAllTask];
}

- (void) setAllRequestPriorityLevel:(PriorityLevel) level
{    
    NSArray * allTasks = [self tasks];
    for (YTask *  task in allTasks) 
    {
        [task setQueuePriority:level];
    }
}

- (void) stopRequestsWithLevel:(PriorityLevel) level
{
    NSArray * allTasks = [self tasks];
    for (YTask *  task in allTasks) 
    {
        if ([task queuePriority] == level) 
        {
            [self stopTask:task];
            [self cancelTask:task];
        }
    }

}
- (void) setRequestPriorityLevel:(PriorityLevel) level withRequestName:(NSString *) requestName
{
    if ([NSString isNilOrEmpty:requestName]) {
        return;
    }
    
    YTask * task = [self taskByName:requestName];
    if(task)
    {
        [task setQueuePriority:level];
    }
}

- (DownloadRequest *) requestForKey :(NSString *) key
{
    if ([NSString isNilOrEmpty:key]) {
        return nil;
    }
    
    if (!self.requestDictionary) {
        return nil;
    }
    
    return [self.requestDictionary objectForKey:key];
}

#pragma mark
#pragma mark DownloadTaskDelegate
- (void) didTaskReceiveDataFinish: (NSData *) theData task:(YDownloaderTask *) task;
{
    DebugLog(@"download task finish, taskName:%@", task.name);
    DownloadRequest * request = [self requestForKey:task.name];
    if (!request) {
        
        DebugLog(@"NOT FOUND REQUEST :%@", task.name);
        return;
    }
    
    [request processOptionWithRequestFinish];
    
    if (!request.delegate) {
        
        DebugLog(@"NOT FOUND REQUEST DELEGATE :%@", task.name);
        return;
    }
    
    if ([request.delegate respondsToSelector:@selector(didTaskReceiveDataFinish: request:)]) 
    {
        [[request delegate] didTaskReceiveDataFinish:theData request:request];
    }
    else {
        DebugLog(@"NOT FOUND REQUEST DELEGATE didTaskReceiveDataFinish :%@", task.name);
    }
    
    [self.requestDictionary removeObjectForKey:request.name];    
}

- (void) didTaskReceiveFilename: (NSString *) aName task:(YDownloaderTask *) task;
{
    DownloadRequest * request = [self requestForKey:task.name];
    if (!request) {
        return;
    }
    
    if (!request.delegate) {
        return;
    }
    
    if ([request.delegate respondsToSelector:@selector(didTaskReceiveFilename: request:)]) 
    {
        [[request delegate] didTaskReceiveFilename:aName request:request];
    }
}

- (void) taskDataDownloadFailed: (NSString *) reason task:(YDownloaderTask *) task;
{
    DebugLog(@"reason:%@   name:%@", reason, task.name);
    
    DownloadRequest * request = [self requestForKey:task.name];
    if (!request) {
        return;
    }
    
    [request processOptionWithRequestFailed];
    
    if (!request.delegate) {
        return;
    }
    
    if ([request.delegate respondsToSelector:@selector(taskDataDownloadFailed: request:)]) 
    {
        [[request delegate] taskDataDownloadFailed:reason request:request];
    }
    
    [self.requestDictionary removeObjectForKey:request.name];
}

- (void) taskDataDownloadAtPercent: (NSNumber *) aPercent task:(YDownloaderTask *) task;
{
    DownloadRequest * request = [self requestForKey:task.name];
    if (!request) {
        return;
    }
    
    if (!request.delegate) {
        return;
    }
    
    if ([request.delegate respondsToSelector:@selector(taskDataDownloadAtPercent: request:)]) 
    {
        [[request delegate] taskDataDownloadAtPercent:aPercent request:request];
    }
}

@end

@interface YDownloaderTask()
{
    NSTimer * exitTime_;
    
    BOOL exit;
}

@property (nonatomic, strong) NSTimer * exitTime;
@end

@implementation YDownloaderTask
@synthesize response = response_;
@synthesize urlconnection = urlconnection_;

@synthesize downloadModel = downloadModel_;
@synthesize recvData = recvData_;

@synthesize delegate = delegate_;
@synthesize timeout;

@synthesize exitTime = exitTime_;

@synthesize url;
- (void) dealloc
{
    [self stopDownload];
    
    YRelease(downloadModel_);
    YRelease(urlconnection_);
    
    YRelease(recvData_);
    YRelease(response_);
    
    YRelease(url)
    YRelease(exitTime_)
    
    [super dealloc];
}

- (id) init
{
    self = [super init];
    if (self) {
        self.downloadModel = Nil;
        self.recvData = Nil;
        self.urlconnection = Nil;
        self.response = Nil;
        
        exit = TRUE;
        self.exitTime = [NSTimer timerWithTimeInterval:0.1f target:self selector:@selector(exitInputSource) userInfo:nil repeats:NO];
        
    }
    return self;
}

- (void) cleanup
{
	self.recvData = nil;
	self.response = nil;
    
	self.urlconnection = nil;
	self.downloadModel = nil;    
}

- (void) stopDownload
{
    [self.urlconnection cancel];
    self.urlconnection = nil;
}

- (void) clearRecvedData
{
    [self.recvData clearData];
}


- (void) stopDownloadAndClearRecvedData
{
    [self stopDownload];
    [self clearRecvedData];
}

- (void) download:(YDownloadObjectModel *) downloadModelValue;
{
    self.downloadModel = downloadModelValue;
    
    if (!downloadModelValue) {
        return;
    }
    
    NSString * strUrl = self.downloadModel.url;
    NSURL * urlHttp = [NSURL URLWithString:strUrl];
    self.url = urlHttp;
}



- (void)exitInputSource
{
//    DebugLog(@"exitInputSource, name:%@, needstop:%d", self.name, self.bNeedStop);
    [self.exitTime invalidate];
}


-(void) addExitTime2CurrentRunLoop
{
    [[NSRunLoop currentRunLoop] addTimer:self.exitTime forMode:NSDefaultRunLoopMode];
}

#pragma mark
#pragma mark YTask
- (void) stop
{
    [super stop];       
    [self addExitTime2CurrentRunLoop];     
//    [self performSelector:@selector(addExitTime2CurrentRunLoop) withObject:nil afterDelay:0.1f];
}


- (void) cancel
{
    [self stop];
    [super cancel];
}

- (void) delegateFailedReason:(NSString *) reason
{
    if (self.delegate &&
        [self.delegate respondsToSelector:@selector(taskDataDownloadFailed:task:)]) 
    {
        [self.delegate taskDataDownloadFailed:reason task:self];
    }
}
- (BOOL) taskBeforeRun
{
    if(![super taskBeforeRun])
    {
        return FALSE;
    }
    
    // to do setup
    if (!self->url) 
    {
        NSString *reason = [NSString stringWithFormat:@"Could not create URL from string %@", self->url];
        DebugLog(reason);
		[self delegateFailedReason:reason];        
        return FALSE;
    }
    
    if ([self->url isFileURL]) 
    { 
        NSString *reason = [NSString stringWithFormat:@"Url is local path %@", self->url];
        DebugLog(reason);
		[self delegateFailedReason:reason];
        return FALSE;
    }
    
    if ([self.recvData bCached]) {
        NSString *reason = [NSString stringWithFormat:@"RecvData is Cached %@", self.recvData];
        DebugLog(reason);
		[self delegateFailedReason:reason];
        if (self.delegate && [self.delegate respondsToSelector:@selector(didTaskReceiveDataFinish: task:)]) 
        {
            [[self delegate] didTaskReceiveDataFinish:self.recvData.data task:self];
        }
        return FALSE;
    }
    
    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:self->url];
	if (!theRequest)
	{
		NSString *reason = [NSString stringWithFormat:@"Could not create URL request from string %@", self->url];
        DebugLog(reason);
		[self delegateFailedReason:reason];
		return FALSE;
	}
    if (self.timeout != 0) 
    {
        [theRequest setTimeoutInterval:self.timeout];
    }
        
    self.urlconnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];
	if (!self.urlconnection)
	{
		NSString *reason = [NSString stringWithFormat:@"URL connection failed for string %@", self->url];
        DebugLog(reason);
		[self delegateFailedReason:reason];
		return FALSE;
	}	    
    
    return TRUE;
}

- (BOOL) taskAfterRun
{
    if(![super taskAfterRun])
    {
        return FALSE;
    }
    
    return TRUE;
}

- (BOOL) run
{
    NSDate* endDate = [NSDate distantFuture];
    NSRunLoop * currentRunLoop = [NSRunLoop currentRunLoop];
    do {
   
        [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:endDate];
        if ([self isCancelled]) 
        {
            DebugLog(@"isCancelled Task:%@", self.name);
            return FALSE;            
        }       
        
    } while (!self.bNeedStop);

    if (self.bNeedStop) 
    {
        [self stopDownload];
    }
    
    if (![self.recvData isRecvFinished]) 
    {
        DebugLog(@"Task Stopped:%@", self.name);
    }    
    else 
    {
        DebugLog(@"Task Finished:%@", self.name);
    }
    return TRUE;
}

#pragma mark
#pragma mark NSURLConnection

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse
{   
    @try 
    {
        // store the response information
        self.response = aResponse;

        [self.recvData setNeedRecvDataLenght:[self.response expectedContentLength]];
        if ([self.response expectedContentLength] < 0)
        {   
            [self.recvData setBCheckRecvDataLenght:NO];    
            if (self.delegate && [self.delegate respondsToSelector:@selector(taskDataDownloadFailed: task:)]) 
            {
                NSString *reason = [NSString stringWithFormat:@"Invalid expectedContentLength [%@]", self->url];
                DebugLog(@"%@",reason);
//                [[self delegate] taskDataDownloadFailed:reason task:self];
            }

            
            /*  ---   保留代码  如果服务端没有告诉 请求内容的长度，就认为url无效 ----- */
            /*
            if (self.delegate && [self.delegate respondsToSelector:@selector(taskDataDownloadFailed: task:)]) 
            {
                NSString *reason = [NSString stringWithFormat:@"Invalid URL [%@]", self.url];
                [[self delegate] taskDataDownloadFailed:reason task:self];
            }
            
            [self stopDownload];
            [self cleanup];
            [self stop];
            return;
             */
        }
        
        if ([aResponse suggestedFilename])
        {
            if (self.delegate && [self.delegate respondsToSelector:@selector(didTaskReceiveFilename: task:)]) 
            {
                [[self delegate] didTaskReceiveFilename:[aResponse suggestedFilename] task:self];
            }
        }            
    }
    @catch (NSException *exception) {
        NSString* debuginfo = [NSString stringWithFormat:@"Error: name: %@ reason: %@", exception.name, exception.reason];
        DebugLog(debuginfo);
        [self stop];
    }
    @finally {
        
    }
       
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
{   
    @try 
    {   
        if (!theData) 
        {
            return;
        }
        
        if(!self.recvData)
        {
            self.recvData = [[[DownloadRecvDataMemory alloc] init] autorelease];
        }            
        
        [self.recvData AppendData:theData];
        if (self.response)
        {
            float expectedLength = [self.response expectedContentLength];
            float currentLength = self.recvData.length;
            float percent = currentLength / expectedLength;
            
            if (self.delegate && [self.delegate respondsToSelector:@selector(taskDataDownloadAtPercent: task:)]) 
            {
                [[self delegate] taskDataDownloadAtPercent:NUMBER(percent) task:self];
            }
        }
    }
    @catch (NSException *exception) {
        NSString* debuginfo = [NSString stringWithFormat:@"Error: name: %@ reason: %@", exception.name, exception.reason];
        DebugLog(debuginfo);
    }
    @finally {
        
    } 
      
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    @try 
    {         
        self.response = nil;	
        [self.recvData processRecvAllDataFinish]; 
//        DebugLog(@"connectionDidFinishLoading:%@", self.name);
        [self.recvData setRecvFinished:TRUE];
             		
        NSData *theData = [self.recvData data] ;
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(didTaskReceiveDataFinish: task:)]) 
        {
            [[self delegate] didTaskReceiveDataFinish:theData task:self];
        }
        
        
        [self stop];
    }
    @catch (NSException *exception) {
        
        NSString* debuginfo = [NSString stringWithFormat:@"Error: name: %@ reason:%@ info:%@", 
                          exception.name,
                          exception.reason,
                          exception.userInfo];
        DebugLog(debuginfo);
        [self stop];
    }
    @finally {
    }
}


- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    @try 
    {
        NSString * errorinfo = [NSString stringWithFormat:@"Error: Failed connection, %@", [error localizedDescription]];
        DebugLog(errorinfo);
        
        [self.recvData processRecvAllDataFalied];
        DebugLog(@"didFailWithError:%@", self.name);
        [self.recvData setRecvFinished:TRUE];
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(taskDataDownloadFailed: task:)]) 
        {
            [[self delegate] taskDataDownloadFailed:errorinfo task:self];
        }
        [self stop];
    }
    @catch (NSException *exception) {
        NSString* debuginfo = [NSString stringWithFormat:@"Error: name: %@ reason: %@", exception.name, exception.reason];
        DebugLog(debuginfo);
        [self stop];
    }
    @finally {
        
    }    
}




@end











